home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / iPod / iPodderX.sit / iPodderX / iPodderX.app / Contents / Resources / StorageWrapper.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2005-01-07  |  24.5 KB  |  678 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.3)
  3.  
  4. from sha import sha
  5. from threading import Event
  6. from bitfield import Bitfield
  7.  
  8. def dummy_status(fractionDone = None, activity = None):
  9.     pass
  10.  
  11.  
  12. def dummy_data_flunked(size):
  13.     pass
  14.  
  15.  
  16. class StorageWrapper:
  17.     
  18.     def __init__(self, storage, request_size, hashes, piece_size, finished, failed, statusfunc = dummy_status, flag = Event(), check_hashes = True, data_flunked = dummy_data_flunked):
  19.         self.storage = storage
  20.         self.request_size = request_size
  21.         self.hashes = hashes
  22.         self.piece_size = piece_size
  23.         self.data_flunked = data_flunked
  24.         self.total_length = storage.get_total_length()
  25.         self.amount_left = self.total_length
  26.         if self.total_length <= piece_size * (len(hashes) - 1):
  27.             raise ValueError, 'bad data from tracker - total too small'
  28.         
  29.         if self.total_length > piece_size * len(hashes):
  30.             raise ValueError, 'bad data from tracker - total too big'
  31.         
  32.         self.finished = finished
  33.         self.failed = failed
  34.         self.numactive = [
  35.             0] * len(hashes)
  36.         self.inactive_requests = [
  37.             1] * len(hashes)
  38.         self.amount_inactive = self.total_length
  39.         self.endgame = False
  40.         self.have = Bitfield(len(hashes))
  41.         self.waschecked = [
  42.             check_hashes] * len(hashes)
  43.         self.places = { }
  44.         self.holes = []
  45.         if len(hashes) == 0:
  46.             finished()
  47.             return None
  48.         
  49.         targets = { }
  50.         total = len(hashes)
  51.         for i in xrange(len(hashes)):
  52.             if not self._waspre(i):
  53.                 targets.setdefault(hashes[i], []).append(i)
  54.                 total -= 1
  55.                 continue
  56.         
  57.         numchecked = 0.0
  58.         if total and check_hashes:
  59.             statusfunc({
  60.                 'activity': 'checking existing file',
  61.                 'fractionDone': 0 })
  62.         
  63.         
  64.         def markgot(piece, pos, self = self, check_hashes = check_hashes):
  65.             self.places[piece] = pos
  66.             self.have[piece] = True
  67.             self.amount_left -= self._piecelen(piece)
  68.             self.amount_inactive -= self._piecelen(piece)
  69.             self.inactive_requests[piece] = None
  70.             self.waschecked[piece] = check_hashes
  71.  
  72.         lastlen = self._piecelen(len(hashes) - 1)
  73.         for i in xrange(len(hashes)):
  74.             if not self._waspre(i):
  75.                 self.holes.append(i)
  76.                 continue
  77.             if not check_hashes:
  78.                 markgot(i, i)
  79.                 continue
  80.             sh = sha(self.storage.read(piece_size * i, lastlen))
  81.             sp = sh.digest()
  82.             sh.update(self.storage.read(piece_size * i + lastlen, self._piecelen(i) - lastlen))
  83.             s = sh.digest()
  84.             if s == hashes[i]:
  85.                 markgot(i, i)
  86.             elif targets.get(s) and self._piecelen(i) == self._piecelen(targets[s][-1]):
  87.                 markgot(targets[s].pop(), i)
  88.             elif not self.have[len(hashes) - 1] and sp == hashes[-1] and i == len(hashes) - 1 or not self._waspre(len(hashes) - 1):
  89.                 markgot(len(hashes) - 1, i)
  90.             else:
  91.                 self.places[i] = i
  92.             if flag.isSet():
  93.                 return None
  94.             
  95.             numchecked += 1
  96.             statusfunc({
  97.                 'fractionDone': 1 - float(self.amount_left) / self.total_length })
  98.         
  99.         if self.amount_left == 0:
  100.             finished()
  101.         
  102.  
  103.     
  104.     def _waspre(self, piece):
  105.         return self.storage.was_preallocated(piece * self.piece_size, self._piecelen(piece))
  106.  
  107.     
  108.     def _piecelen(self, piece):
  109.         if piece < len(self.hashes) - 1:
  110.             return self.piece_size
  111.         else:
  112.             return self.total_length - piece * self.piece_size
  113.  
  114.     
  115.     def get_amount_left(self):
  116.         return self.amount_left
  117.  
  118.     
  119.     def do_I_have_anything(self):
  120.         return self.amount_left < self.total_length
  121.  
  122.     
  123.     def _make_inactive(self, index):
  124.         length = min(self.piece_size, self.total_length - self.piece_size * index)
  125.         l = []
  126.         x = 0
  127.         while x + self.request_size < length:
  128.             l.append((x, self.request_size))
  129.             x += self.request_size
  130.         l.append((x, length - x))
  131.         self.inactive_requests[index] = l
  132.  
  133.     
  134.     def is_endgame(self):
  135.         return self.endgame
  136.  
  137.     
  138.     def get_have_list(self):
  139.         return self.have.tostring()
  140.  
  141.     
  142.     def do_I_have(self, index):
  143.         return self.have[index]
  144.  
  145.     
  146.     def do_I_have_requests(self, index):
  147.         return not (not self.inactive_requests[index])
  148.  
  149.     
  150.     def new_request(self, index):
  151.         if self.inactive_requests[index] == 1:
  152.             self._make_inactive(index)
  153.         
  154.         self.numactive[index] += 1
  155.         rs = self.inactive_requests[index]
  156.         r = min(rs)
  157.         rs.remove(r)
  158.         self.amount_inactive -= r[1]
  159.         if self.amount_inactive == 0:
  160.             self.endgame = True
  161.         
  162.         return r
  163.  
  164.     
  165.     def piece_came_in(self, index, begin, piece):
  166.         
  167.         try:
  168.             return self._piece_came_in(index, begin, piece)
  169.         except IOError:
  170.             e = None
  171.             self.failed('IO Error ' + str(e))
  172.             return True
  173.  
  174.  
  175.     
  176.     def _piece_came_in(self, index, begin, piece):
  177.         if not self.places.has_key(index):
  178.             n = self.holes.pop(0)
  179.             if self.places.has_key(n):
  180.                 oldpos = self.places[n]
  181.                 old = self.storage.read(self.piece_size * oldpos, self._piecelen(n))
  182.                 if self.have[n] and sha(old).digest() != self.hashes[n]:
  183.                     self.failed('data corrupted on disk - maybe you have two copies running?')
  184.                     return True
  185.                 
  186.                 self.storage.write(self.piece_size * n, old)
  187.                 self.places[n] = n
  188.                 if index == oldpos or index in self.holes:
  189.                     self.places[index] = oldpos
  190.                 else:
  191.                     for p, v in self.places.items():
  192.                         if v == index:
  193.                             break
  194.                             continue
  195.                     
  196.                     self.places[index] = index
  197.                     self.places[p] = oldpos
  198.                     old = self.storage.read(self.piece_size * index, self.piece_size)
  199.                     self.storage.write(self.piece_size * oldpos, old)
  200.             elif index in self.holes or index == n:
  201.                 if not self._waspre(n):
  202.                     self.storage.write(self.piece_size * n, self._piecelen(n) * chr(255))
  203.                 
  204.                 self.places[index] = n
  205.             else:
  206.                 for p, v in self.places.items():
  207.                     if v == index:
  208.                         break
  209.                         continue
  210.                 
  211.                 self.places[index] = index
  212.                 self.places[p] = n
  213.                 old = self.storage.read(self.piece_size * index, self._piecelen(n))
  214.                 self.storage.write(self.piece_size * n, old)
  215.         
  216.         self.storage.write(self.places[index] * self.piece_size + begin, piece)
  217.         self.numactive[index] -= 1
  218.         return True
  219.  
  220.     
  221.     def request_lost(self, index, begin, length):
  222.         self.inactive_requests[index].append((begin, length))
  223.         self.amount_inactive += length
  224.         self.numactive[index] -= 1
  225.  
  226.     
  227.     def get_piece(self, index, begin, length):
  228.         
  229.         try:
  230.             return self._get_piece(index, begin, length)
  231.         except IOError:
  232.             e = None
  233.             self.failed('IO Error ' + str(e))
  234.             return None
  235.  
  236.  
  237.     
  238.     def _get_piece(self, index, begin, length):
  239.         if not self.have[index]:
  240.             return None
  241.         
  242.         if not self.waschecked[index]:
  243.             if sha(self.storage.read(self.piece_size * self.places[index], self._piecelen(index))).digest() != self.hashes[index]:
  244.                 self.failed('told file complete on start-up, but piece failed hash check')
  245.                 return None
  246.             
  247.             self.waschecked[index] = True
  248.         
  249.         if begin + length > self._piecelen(index):
  250.             return None
  251.         
  252.         return self.storage.read(self.piece_size * self.places[index] + begin, length)
  253.  
  254.  
  255.  
  256. class DummyStorage:
  257.     
  258.     def __init__(self, total, pre = False, ranges = []):
  259.         self.pre = pre
  260.         self.ranges = ranges
  261.         self.s = chr(255) * total
  262.         self.done = False
  263.  
  264.     
  265.     def was_preexisting(self):
  266.         return self.pre
  267.  
  268.     
  269.     def was_preallocated(self, begin, length):
  270.         for b, l in self.ranges:
  271.             if begin >= b and begin + length <= b + l:
  272.                 return True
  273.                 continue
  274.         
  275.         return False
  276.  
  277.     
  278.     def get_total_length(self):
  279.         return len(self.s)
  280.  
  281.     
  282.     def read(self, begin, length):
  283.         return self.s[begin:begin + length]
  284.  
  285.     
  286.     def write(self, begin, piece):
  287.         self.s = self.s[:begin] + piece + self.s[begin + len(piece):]
  288.  
  289.     
  290.     def finished(self):
  291.         self.done = True
  292.  
  293.  
  294.  
  295. def test_basic():
  296.     ds = DummyStorage(3)
  297.     sw = StorageWrapper(ds, 2, [
  298.         sha('abc').digest()], 4, ds.finished, None)
  299.     if not sw.get_amount_left() == 3:
  300.         raise AssertionError
  301.     if not not sw.do_I_have_anything():
  302.         raise AssertionError
  303.     if not sw.get_have_list() == chr(0):
  304.         raise AssertionError
  305.     if not sw.do_I_have_requests(0):
  306.         raise AssertionError
  307.     x = []
  308.     x.append(sw.new_request(0))
  309.     if not sw.do_I_have_requests(0):
  310.         raise AssertionError
  311.     x.append(sw.new_request(0))
  312.     if not not sw.do_I_have_requests(0):
  313.         raise AssertionError
  314.     x.sort()
  315.     if not x == [
  316.         (0, 2),
  317.         (2, 1)]:
  318.         raise AssertionError
  319.     sw.request_lost(0, 2, 1)
  320.     del x[-1]
  321.     if not sw.do_I_have_requests(0):
  322.         raise AssertionError
  323.     x.append(sw.new_request(0))
  324.     if not x == [
  325.         (0, 2),
  326.         (2, 1)]:
  327.         raise AssertionError
  328.     if not not sw.do_I_have_requests(0):
  329.         raise AssertionError
  330.     sw.piece_came_in(0, 0, 'ab')
  331.     if not not sw.do_I_have_requests(0):
  332.         raise AssertionError
  333.     if not sw.get_amount_left() == 3:
  334.         raise AssertionError
  335.     if not not sw.do_I_have_anything():
  336.         raise AssertionError
  337.     if not sw.get_have_list() == chr(0):
  338.         raise AssertionError
  339.     if not not (ds.done):
  340.         raise AssertionError
  341.     sw.piece_came_in(0, 2, 'c')
  342.     if not not sw.do_I_have_requests(0):
  343.         raise AssertionError
  344.     if not sw.get_amount_left() == 0:
  345.         raise AssertionError
  346.     if not sw.do_I_have_anything():
  347.         raise AssertionError
  348.     if not sw.get_have_list() == chr(128):
  349.         raise AssertionError
  350.     if not sw.get_piece(0, 0, 3) == 'abc':
  351.         raise AssertionError
  352.     if not sw.get_piece(0, 1, 2) == 'bc':
  353.         raise AssertionError
  354.     if not sw.get_piece(0, 0, 2) == 'ab':
  355.         raise AssertionError
  356.     if not sw.get_piece(0, 1, 1) == 'b':
  357.         raise AssertionError
  358.     if not ds.done:
  359.         raise AssertionError
  360.  
  361.  
  362. def test_two_pieces():
  363.     ds = DummyStorage(4)
  364.     sw = StorageWrapper(ds, 3, [
  365.         sha('abc').digest(),
  366.         sha('d').digest()], 3, ds.finished, None)
  367.     if not sw.get_amount_left() == 4:
  368.         raise AssertionError
  369.     if not not sw.do_I_have_anything():
  370.         raise AssertionError
  371.     if not sw.get_have_list() == chr(0):
  372.         raise AssertionError
  373.     if not sw.do_I_have_requests(0):
  374.         raise AssertionError
  375.     if not sw.do_I_have_requests(1):
  376.         raise AssertionError
  377.     if not sw.new_request(0) == (0, 3):
  378.         raise AssertionError
  379.     if not sw.get_amount_left() == 4:
  380.         raise AssertionError
  381.     if not not sw.do_I_have_anything():
  382.         raise AssertionError
  383.     if not sw.get_have_list() == chr(0):
  384.         raise AssertionError
  385.     if not not sw.do_I_have_requests(0):
  386.         raise AssertionError
  387.     if not sw.do_I_have_requests(1):
  388.         raise AssertionError
  389.     if not sw.new_request(1) == (0, 1):
  390.         raise AssertionError
  391.     if not sw.get_amount_left() == 4:
  392.         raise AssertionError
  393.     if not not sw.do_I_have_anything():
  394.         raise AssertionError
  395.     if not sw.get_have_list() == chr(0):
  396.         raise AssertionError
  397.     if not not sw.do_I_have_requests(0):
  398.         raise AssertionError
  399.     if not not sw.do_I_have_requests(1):
  400.         raise AssertionError
  401.     sw.piece_came_in(0, 0, 'abc')
  402.     if not sw.get_amount_left() == 1:
  403.         raise AssertionError
  404.     if not sw.do_I_have_anything():
  405.         raise AssertionError
  406.     if not sw.get_have_list() == chr(128):
  407.         raise AssertionError
  408.     if not not sw.do_I_have_requests(0):
  409.         raise AssertionError
  410.     if not not sw.do_I_have_requests(1):
  411.         raise AssertionError
  412.     if not sw.get_piece(0, 0, 3) == 'abc':
  413.         raise AssertionError
  414.     if not not (ds.done):
  415.         raise AssertionError
  416.     sw.piece_came_in(1, 0, 'd')
  417.     if not ds.done:
  418.         raise AssertionError
  419.     if not sw.get_amount_left() == 0:
  420.         raise AssertionError
  421.     if not sw.do_I_have_anything():
  422.         raise AssertionError
  423.     if not sw.get_have_list() == chr(192):
  424.         raise AssertionError
  425.     if not not sw.do_I_have_requests(0):
  426.         raise AssertionError
  427.     if not not sw.do_I_have_requests(1):
  428.         raise AssertionError
  429.     if not sw.get_piece(1, 0, 1) == 'd':
  430.         raise AssertionError
  431.  
  432.  
  433. def test_hash_fail():
  434.     ds = DummyStorage(4)
  435.     sw = StorageWrapper(ds, 4, [
  436.         sha('abcd').digest()], 4, ds.finished, None)
  437.     if not sw.get_amount_left() == 4:
  438.         raise AssertionError
  439.     if not not sw.do_I_have_anything():
  440.         raise AssertionError
  441.     if not sw.get_have_list() == chr(0):
  442.         raise AssertionError
  443.     if not sw.do_I_have_requests(0):
  444.         raise AssertionError
  445.     if not sw.new_request(0) == (0, 4):
  446.         raise AssertionError
  447.     sw.piece_came_in(0, 0, 'abcx')
  448.     if not sw.get_amount_left() == 4:
  449.         raise AssertionError
  450.     if not not sw.do_I_have_anything():
  451.         raise AssertionError
  452.     if not sw.get_have_list() == chr(0):
  453.         raise AssertionError
  454.     if not sw.do_I_have_requests(0):
  455.         raise AssertionError
  456.     if not sw.new_request(0) == (0, 4):
  457.         raise AssertionError
  458.     if not not (ds.done):
  459.         raise AssertionError
  460.     sw.piece_came_in(0, 0, 'abcd')
  461.     if not ds.done:
  462.         raise AssertionError
  463.     if not sw.get_amount_left() == 0:
  464.         raise AssertionError
  465.     if not sw.do_I_have_anything():
  466.         raise AssertionError
  467.     if not sw.get_have_list() == chr(128):
  468.         raise AssertionError
  469.     if not not sw.do_I_have_requests(0):
  470.         raise AssertionError
  471.  
  472.  
  473. def test_lazy_hashing():
  474.     ds = DummyStorage(4, ranges = [
  475.         (0, 4)])
  476.     flag = Event()
  477.     sw = StorageWrapper(ds, 4, [
  478.         sha('abcd').digest()], 4, ds.finished, (lambda x, flag = flag: flag.set()), check_hashes = False)
  479.     if not sw.get_piece(0, 0, 2) is None:
  480.         raise AssertionError
  481.     if not flag.isSet():
  482.         raise AssertionError
  483.  
  484.  
  485. def test_lazy_hashing_pass():
  486.     ds = DummyStorage(4)
  487.     flag = Event()
  488.     sw = StorageWrapper(ds, 4, [
  489.         sha(chr(255) * 4).digest()], 4, ds.finished, (lambda x, flag = flag: flag.set()), check_hashes = False)
  490.     if not sw.get_piece(0, 0, 2) is None:
  491.         raise AssertionError
  492.     if not not flag.isSet():
  493.         raise AssertionError
  494.  
  495.  
  496. def test_preexisting():
  497.     ds = DummyStorage(4, True, [
  498.         (0, 4)])
  499.     sw = StorageWrapper(ds, 2, [
  500.         sha(chr(255) * 2).digest(),
  501.         sha('ab').digest()], 2, ds.finished, None)
  502.     if not sw.get_amount_left() == 2:
  503.         raise AssertionError
  504.     if not sw.do_I_have_anything():
  505.         raise AssertionError
  506.     if not sw.get_have_list() == chr(128):
  507.         raise AssertionError
  508.     if not not sw.do_I_have_requests(0):
  509.         raise AssertionError
  510.     if not sw.do_I_have_requests(1):
  511.         raise AssertionError
  512.     if not sw.new_request(1) == (0, 2):
  513.         raise AssertionError
  514.     if not not (ds.done):
  515.         raise AssertionError
  516.     sw.piece_came_in(1, 0, 'ab')
  517.     if not ds.done:
  518.         raise AssertionError
  519.     if not sw.get_amount_left() == 0:
  520.         raise AssertionError
  521.     if not sw.do_I_have_anything():
  522.         raise AssertionError
  523.     if not sw.get_have_list() == chr(192):
  524.         raise AssertionError
  525.     if not not sw.do_I_have_requests(0):
  526.         raise AssertionError
  527.     if not not sw.do_I_have_requests(1):
  528.         raise AssertionError
  529.  
  530.  
  531. def test_total_too_short():
  532.     ds = DummyStorage(4)
  533.     
  534.     try:
  535.         StorageWrapper(ds, 4, [
  536.             sha(chr(255) * 4).digest(),
  537.             sha(chr(255) * 4).digest()], 4, ds.finished, None)
  538.         raise 'fail'
  539.     except ValueError:
  540.         pass
  541.  
  542.  
  543.  
  544. def test_total_too_big():
  545.     ds = DummyStorage(9)
  546.     
  547.     try:
  548.         sw = StorageWrapper(ds, 4, [
  549.             sha('qqqq').digest(),
  550.             sha(chr(255) * 4).digest()], 4, ds.finished, None)
  551.         raise 'fail'
  552.     except ValueError:
  553.         pass
  554.  
  555.  
  556.  
  557. def test_end_above_total_length():
  558.     ds = DummyStorage(3, True)
  559.     sw = StorageWrapper(ds, 4, [
  560.         sha('qqq').digest()], 4, ds.finished, None)
  561.     if not sw.get_piece(0, 0, 4) == None:
  562.         raise AssertionError
  563.  
  564.  
  565. def test_end_past_piece_end():
  566.     ds = DummyStorage(4, True, ranges = [
  567.         (0, 4)])
  568.     sw = StorageWrapper(ds, 4, [
  569.         sha(chr(255) * 2).digest(),
  570.         sha(chr(255) * 2).digest()], 2, ds.finished, None)
  571.     if not ds.done:
  572.         raise AssertionError
  573.     if not sw.get_piece(0, 0, 3) == None:
  574.         raise AssertionError
  575.  
  576. from random import shuffle
  577.  
  578. def test_alloc_random():
  579.     ds = DummyStorage(101)
  580.     sw = 1([], [], [ sha(chr(i)).digest() for i in xrange(101) ], 1, ds.finished, None)
  581.     for i in xrange(100):
  582.         if not sw.new_request(i) == (0, 1):
  583.             raise AssertionError
  584.         ds
  585.     
  586.     r = range(100)
  587.     shuffle(r)
  588.     for i in r:
  589.         sw.piece_came_in(i, 0, chr(i))
  590.     
  591.     for i in xrange(100):
  592.         if not sw.get_piece(i, 0, 1) == chr(i):
  593.             raise AssertionError
  594.         StorageWrapper
  595.     
  596.     if not [] == []([ chr(i) for i in xrange(100) ]):
  597.         raise AssertionError
  598.     ''.join
  599.  
  600.  
  601. def test_alloc_resume():
  602.     ds = DummyStorage(101)
  603.     sw = 1([], [], [ sha(chr(i)).digest() for i in xrange(101) ], 1, ds.finished, None)
  604.     for i in xrange(100):
  605.         if not sw.new_request(i) == (0, 1):
  606.             raise AssertionError
  607.         ds
  608.     
  609.     r = range(100)
  610.     shuffle(r)
  611.     for i in r[:50]:
  612.         sw.piece_came_in(i, 0, chr(i))
  613.     
  614.     if not ds.s[50:] == chr(255) * 51:
  615.         raise AssertionError
  616.     StorageWrapper
  617.     ds.ranges = [
  618.         (0, 50)]
  619.     sw = 1([], [], [ sha(chr(i)).digest() for i in xrange(101) ], 1, ds.finished, None)
  620.     for i in r[50:]:
  621.         sw.piece_came_in(i, 0, chr(i))
  622.     
  623.     if not [] == []([ chr(i) for i in xrange(100) ]):
  624.         raise AssertionError
  625.     ''.join
  626.  
  627.  
  628. def test_last_piece_pre():
  629.     ds = DummyStorage(3, ranges = [
  630.         (2, 1)])
  631.     ds.s = chr(255) + chr(255) + 'c'
  632.     sw = StorageWrapper(ds, 2, [
  633.         sha('ab').digest(),
  634.         sha('c').digest()], 2, ds.finished, None)
  635.     if not not sw.do_I_have_requests(1):
  636.         raise AssertionError
  637.     if not sw.do_I_have_requests(0):
  638.         raise AssertionError
  639.  
  640.  
  641. def test_not_last_pre():
  642.     ds = DummyStorage(3, ranges = [
  643.         (1, 1)])
  644.     ds.s = chr(255) + 'a' + chr(255)
  645.     sw = StorageWrapper(ds, 1, [
  646.         sha('a').digest()] * 3, 1, ds.finished, None)
  647.     if not not sw.do_I_have_requests(1):
  648.         raise AssertionError
  649.     if not sw.do_I_have_requests(0):
  650.         raise AssertionError
  651.     if not sw.do_I_have_requests(2):
  652.         raise AssertionError
  653.  
  654.  
  655. def test_last_piece_not_pre():
  656.     ds = DummyStorage(51, ranges = [
  657.         (50, 1)])
  658.     sw = StorageWrapper(ds, 2, [
  659.         sha('aa').digest()] * 25 + [
  660.         sha('b').digest()], 2, ds.finished, None)
  661.     for i in xrange(25):
  662.         if not sw.new_request(i) == (0, 2):
  663.             raise AssertionError
  664.     
  665.     if not sw.new_request(25) == (0, 1):
  666.         raise AssertionError
  667.     sw.piece_came_in(25, 0, 'b')
  668.     r = range(25)
  669.     shuffle(r)
  670.     for i in r:
  671.         sw.piece_came_in(i, 0, 'aa')
  672.     
  673.     if not ds.done:
  674.         raise AssertionError
  675.     if not ds.s == 'a' * 50 + 'b':
  676.         raise AssertionError
  677.  
  678.